package org.beetlframework.mvc.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.beetlframework.InstanceFactory;
import org.beetlframework.ioc.BeanContext;
import org.beetlframework.mvc.Handler;
import org.beetlframework.mvc.HandlerInvoker;
import org.beetlframework.mvc.ViewResolver;

/**
 * beetl处理器调用
 * @author 草原狼
 * @date 2016-10-4
 */
public class BeetlHandlerInvoker implements HandlerInvoker{
	private ViewResolver viewResolver = InstanceFactory.getViewResolver();
	@Override
	public void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler)
			throws Exception {
		// 获取 Action 相关信息
        Class<?> actionClass = handler.getActionClass();
        Method actionMethod = handler.getActionMethod();
        // 从 BeanHelper 中创建 Action 实例
        Object actionInstance = BeanContext.getBean(actionClass);
        // 检查参数列表是否合法
        checkParamList(actionMethod);
        // 调用 Action 方法
        Object actionMethodResult = invokeActionMethod(actionMethod, actionInstance);
        // 解析视图
        viewResolver.resolveView(request, response, actionMethodResult);
	}
	
	private void checkParamList(Method actionMethod) {
		// 判断 Action 方法参数的个数是否匹配
        Class<?>[] actionMethodParameterTypes = actionMethod.getParameterTypes();
        if (actionMethodParameterTypes.length > 0) {
        	String method = actionMethod.getDeclaringClass().getName()+"."+actionMethod.getName()+"(...)";
            String message = String.format("控制层Action方法不需要参数，你在%s方法定义了%d个参数", method,actionMethodParameterTypes.length);
            throw new RuntimeException(message);
        }
	}

	private Object invokeActionMethod(Method actionMethod, Object actionInstance) throws IllegalAccessException, InvocationTargetException {
        // 通过反射调用 Action 方法
        actionMethod.setAccessible(true); // 取消类型安全检测（可提高反射性能）
        return actionMethod.invoke(actionInstance);
    }

}
